home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / appl / napsaterm / nio.c < prev    next >
C/C++ Source or Header  |  1994-05-14  |  25KB  |  1,194 lines

  1. RCS_ID_C="$Id: nio.c,v 3.5 1994/05/14 12:39:24 ppessi Exp $";
  2. /*
  3.  * nio.c - Generalized I/O (input from almost anywhere!)
  4.  *
  5.  * Author: ppessi <Pekka.Pessi@hut.fi>
  6.  *
  7.  * Copyright (c) 1993 Pekka Pessi
  8.  *
  9.  * Created      : Sun Nov  7 07:45:34 1993 ppessi
  10.  * Last modified: Sat May 14 15:38:31 1994 ppessi
  11.  *
  12.  * $Log: nio.c,v $
  13.  * Revision 3.5  1994/05/14  12:39:24  ppessi
  14.  * Added support for telnet.  Fixed a couple of bugs in rlogin code.
  15.  *
  16.  * Revision 3.4  1994/02/25  16:08:03  ppessi
  17.  * Added the usergroup.library usage
  18.  *
  19.  * Revision 3.3  1994/02/25  02:04:12  ppessi
  20.  * Changed slightly the const defintions for np.title
  21.  *
  22.  * Revision 3.2  1994/01/08  08:56:33  ppessi
  23.  * Removed <stdio.h> from includes
  24.  *
  25.  * Revision 3.1  94/01/07  22:51:41  ppessi
  26.  * Version 3 beta
  27.  * 
  28.  * Revision 2.0  93/11/15  03:42:39  ppessi
  29.  * Version 2 initial revision
  30.  * 
  31.  */
  32.  
  33. #include "amiga.h"
  34. #include "napsaprefs.h"
  35. #include "nio.h"
  36. #include "display.h"
  37. #include <stdlib.h>
  38.  
  39. #if USE_SERIAL || USE_STDIO
  40. struct MsgPort *iop = NULL;
  41. #endif
  42. #if USE_SERIAL || USE_STDIO || USE_RLOGIN
  43. #define INBUFSIZE 512
  44. char inbuf[INBUFSIZE];
  45. #endif
  46. char iobuf[BUFSIZE];
  47.  
  48. int errno;
  49.  
  50. /*
  51.  * Generic functions
  52.  */
  53. long nopen_generic(char **hostvector) { return 0L; }
  54. long nnread_generic(char *buf, long length) { return -1; } 
  55. long nwrite_generic(char *buf, long length) { return -1; }
  56. void niosize_generic(ushort s, ushort t, ushort u, ushort v) { }
  57. void nioctl_generic(int code, int arg1, int arg2) { }
  58. void nclose_generic(void) { }
  59. int  nabort_generic(void) { return 0; }
  60.  
  61. /*
  62.  * This is a 'virtual function table' for nio
  63.  */
  64. struct niotable {
  65.   /* Open nio stream */
  66.   long (*nopen)(char **hostvector);
  67.   /* Read from nio stream */
  68.   long (*nnread)(char *buf, long length);
  69.   /* Write to nio stream */
  70.   long (*nwrite)(char *buf, long length);
  71.   /* Set window size */
  72.   void (*niosize)(ushort, ushort, ushort, ushort);
  73.   /* Send IOCTL command */
  74.   void (*nioctl)(int code, int arg1, int arg2);
  75.   /* Close nio stream */
  76.   void (*nclose)(void);
  77.   /* Abort IO or Resume to IO temporarily */
  78.   int  (*nabort)(void);
  79. }; 
  80.  
  81. extern struct niotable nio_serial;
  82. extern struct niotable nio_stdio;
  83. extern struct niotable nio_dnet;
  84. extern struct niotable nio_rlogin;
  85. extern struct niotable nio_telnet;
  86.  
  87. struct niotable *niotable = 
  88. #if USE_RLOGIN
  89.   &nio_rlogin;
  90. enum iotype iotype = rlogin;
  91. #elif USE_TELNET
  92.   &nio_telnet;
  93. enum iotype iotype = telnet;
  94. #elif USE_SERIAL
  95.   &nio_serial;
  96. enum iotype iotype = serial;
  97. #elif USE_DNET
  98.   &nio_dnet;
  99. enum iotype iotype = dnet;
  100. #elif USE_STDIO
  101.   &nio_stdio;
  102. enum iotype iotype = stdio;
  103. #else
  104. #error No IO method defined
  105. #endif
  106.  
  107. /*
  108.  * Initialize nioinit structure
  109.  */
  110. void 
  111. ninit(enum iotype iotype)
  112. {
  113.   switch (iotype) {
  114. #if USE_SERIAL
  115.   case serial: 
  116.     niotable = &nio_serial;
  117.     return;
  118. #endif
  119. #if USE_STDIO
  120.   case stdio:
  121.     niotable = &nio_stdio;
  122.     return;
  123. #endif
  124. #if USE_DNET
  125.   case dnet: 
  126.     niotable = &nio_dnet;
  127.     return;
  128. #endif
  129. #if USE_RLOGIN
  130.   case rlogin:
  131.     niotable = &nio_rlogin;
  132.     return;
  133. #endif
  134. #if USE_TELNET
  135.   case telnet:
  136.     niotable = &nio_telnet;
  137.     return;
  138. #endif
  139.   default:
  140.     fatalError("no support for %s in this version",
  141.            iotype == serial ? "serial devices" : 
  142.            (iotype == stdio  ? "AmigaDOS IO" :
  143.         (iotype == dnet ? "dnet" : 
  144.          (iotype == telnet ? "telnet" : "rlogin"))));
  145.   }
  146. }
  147.  
  148. /*
  149.  * Virtual functions
  150.  */
  151. long nopen(char **hostvector) 
  152. {
  153.   return (*niotable->nopen)(hostvector);
  154. }
  155.  
  156. long nnread(char *buf, long length)
  157. {
  158.   return (*niotable->nnread)(buf, length);
  159. }
  160.  
  161. long nwrite(char *buf, long length) 
  162. {
  163.   return (*niotable->nwrite)(buf, length);
  164. }
  165.  
  166. void niosize(ushort s, ushort t, ushort u, ushort v)
  167. {
  168.   (*niotable->niosize)(s, t, u, v);
  169. }
  170.  
  171. void nioctl(int code, int arg1, int arg2)
  172. {
  173.   (*niotable->nioctl)(code, arg1, arg2);
  174. }
  175.  
  176. int  nabort(void)
  177. {
  178.   return (*niotable->nabort)();
  179. }
  180.  
  181. void nclose(void)
  182. {
  183.   (*niotable->nclose)();
  184. }
  185.  
  186. #if USE_SERIAL
  187. /* 
  188.  * Define serial IO routines
  189.  */
  190.  
  191. #include <devices/serial.h>
  192.  
  193. static int serial_is_open = 0;
  194. static int aborted = 0;
  195. static struct IOExtSer *inreq = NULL, *outreq = NULL;
  196.  
  197. /*
  198.  * Open a nio channel
  199.  */
  200. long nopen_serial(char **hv)
  201. {
  202.   if (!(iop = CreateMsgPort()) ||
  203.       !(inreq = (struct IOExtSer *)CreateIORequest(iop, sizeof(*inreq))) ||
  204.       !(outreq = (struct IOExtSer *)CreateIORequest(iop, sizeof(*outreq))) ||
  205.       (inreq->io_SerFlags |= SERF_RAD_BOOGIE|(np.shared ? SERF_SHARED : 0),
  206.        OpenDevice(np.device, np.unit, (struct IORequest *)inreq, 0))) {
  207.     fatalError("Unable to open %s unit %ld.", np.device, itos(np.unit));
  208.   }
  209.  
  210.   serial_is_open = 1;
  211.  
  212.   /* Set speed */
  213.   inreq->io_Baud = np.bps;
  214.   inreq->IOSer.io_Command = SDCMD_SETPARAMS;
  215.   DoIO(inreq);
  216.  
  217.   *(outreq) = *(inreq);
  218.   inreq->IOSer.io_Command = CMD_READ;
  219.   inreq->IOSer.io_Data = (APTR)inbuf;
  220.   inreq->IOSer.io_Length = (ULONG)1;
  221.   /* inreq->IOSer.io_Flags = IOB_QUICK; */
  222.   SendIO((struct IORequest *)inreq);
  223.  
  224.   return 1 << iop->mp_SigBit;
  225. }
  226.  
  227. /*
  228.  * Read characters from line
  229.  */
  230. long nnread_serial(char *buf, long length)
  231. {
  232.   long ret, save;
  233.  
  234.   if (GetMsg(iop)) {
  235.     buf[0] = inbuf[0] & 127;
  236.     inreq->IOSer.io_Command = SDCMD_QUERY;
  237.     DoIO((struct IORequest *)inreq);
  238.     save = inreq->IOSer.io_Actual;
  239.     if (ret = MIN(inreq->IOSer.io_Actual, length)) {
  240.       inreq->IOSer.io_Command = CMD_READ;
  241.       inreq->IOSer.io_Data = (APTR)(buf+1);
  242.       inreq->IOSer.io_Length = (ULONG)ret;
  243.       DoIO((struct IORequest *)inreq);
  244.  
  245.       if (inreq->IOSer.io_Error) {
  246.     if (inreq->IOSer.io_Error == 12) 
  247.       termout("\n**** Serial Buffer Overflow;  CLEARING BUFFERS\n", 50);
  248.     else
  249.       termout("**** Serial Device Error; CLEARING BUFFERS\n", 43);
  250.     inreq->IOSer.io_Command = CMD_CLEAR;
  251.     DoIO((struct IORequest *)inreq);
  252.       }
  253.  
  254.       ret = inreq->IOSer.io_Actual;
  255.     }
  256.     inreq->IOSer.io_Command = CMD_READ;
  257.     inreq->IOSer.io_Data = (APTR)inbuf;
  258.     inreq->IOSer.io_Length = (ULONG)1;
  259.     SendIO((struct IORequest *)inreq);
  260.     return ret + 1;
  261.   }
  262.   else 
  263.     return 0;
  264. }
  265.  
  266. long
  267. nwrite_serial(char *buf, long length)
  268. {
  269.   if (!aborted) {
  270.     outreq->IOSer.io_Command = CMD_WRITE;
  271.     outreq->IOSer.io_Data = (APTR)buf;
  272.     outreq->IOSer.io_Length = (ULONG)length;
  273.     DoIO((struct IORequest *)outreq);
  274.     return (long)outreq->IOSer.io_Actual;
  275.   } else {
  276.     return length;
  277.   }
  278. }
  279.  
  280. void nioctl_serial(int code, int arg1, int arg2)
  281. {
  282.   if (aborted)
  283.     return;
  284.  
  285.   if (code == NIO_FLUSH) {
  286.     outreq->IOSer.io_Command = CMD_CLEAR;
  287.     DoIO((struct IORequest *)outreq);
  288.   }
  289.   else if (code == NIO_BREAK) {
  290.     outreq->IOSer.io_Command = SDCMD_BREAK;
  291.     DoIO((struct IORequest *)outreq);
  292.   }
  293. }
  294.  
  295. /* 
  296.  * Toggle unlisten mode.  
  297.  * No serial activity may occur until another nabort() 
  298.  */
  299. int nabort_serial(void) 
  300. {
  301.   if (aborted = !aborted) {
  302.     if (!CheckIO((struct IORequest *)inreq)) {
  303.       AbortIO((struct IORequest *)inreq);
  304.       WaitIO((struct IORequest *)inreq);
  305.     }
  306.   } else {
  307.     /* We know that the inreq is aborted */
  308.     inreq->IOSer.io_Command = CMD_READ;
  309.     inreq->IOSer.io_Data = (APTR)inbuf;
  310.     inreq->IOSer.io_Length = (ULONG)1;
  311.     inreq->IOSer.io_Flags = IOB_QUICK;
  312.     SendIO((struct IORequest *)inreq);
  313.   }
  314.  
  315.   return aborted;
  316. }
  317.  
  318. void nclose_serial(void)
  319. {
  320.   if (inreq) {
  321.     if (serial_is_open) {
  322.       if (!CheckIO((struct IORequest *)inreq)) {
  323.     AbortIO((struct IORequest *)inreq);
  324.     WaitIO((struct IORequest *)inreq);
  325.       }
  326.       CloseDevice((struct IORequest *)inreq);
  327.     }
  328.     DeleteIORequest((struct IORequest *)inreq);
  329.   }
  330.   if (outreq) {
  331.     DeleteIORequest(outreq);
  332.   }
  333.   if (iop) {
  334.     DeleteMsgPort(iop);
  335.   }
  336. }
  337.  
  338. #define niosize_serial niosize_generic
  339.  
  340. struct niotable nio_serial = { 
  341.   nopen_serial,   nnread_serial,    nwrite_serial, 
  342.   niosize_serial, nioctl_serial,    nclose_serial,
  343.   nabort_serial, 
  344. };
  345. #endif /* USE_SERIAL */
  346.  
  347. #if USE_DNET
  348. /* 
  349.  * Define DNET IO routines
  350.  */
  351.  
  352. #include <local/typedefs.h>
  353. #define DeadKeyConvert do_not_use_DeadKeyConvert 
  354. #include <local/suplib_protos.h>
  355. #undef DeadKeyConvert
  356. #include <dnet/channel.h>
  357. #include <lib/dnetlib.h>
  358. #include <server/servers.h>
  359.  
  360. CHANN *io_chan = NULL;
  361.  
  362. /*
  363.  * Open a nio channel
  364.  */
  365. long nopen_dnet(char **hv)
  366. {
  367.   io_chan = (CHANN *)DOpen(NULL, PORT_IALPHATERM, 20, 15);
  368.   if(!io_chan) {
  369.     fatalError("unable to connect to DNet ALPHATERM port");
  370.   }
  371.   DQueue(io_chan, 32);
  372.   return 1 << ((struct MsgPort *)io_chan)->mp_SigBit;
  373. }
  374.  
  375. static void handleioctl(short cmd, short val, char aux)
  376. {
  377.     static short saverows;
  378.  
  379.     if (iotype == dnet) {
  380.     switch (cmd) {
  381. #if 0
  382.     case CIO_MODE:
  383.         Cooked = val;
  384.         break;
  385. #endif
  386.     case CIO_SETROWS:
  387.         saverows = val;
  388.         return;
  389.     case CIO_SETCOLS:
  390.         dssizewindow(saverows, val, 0);
  391.         return;
  392.     }
  393.     } 
  394. }
  395.  
  396. long nnread_dnet(char *buf, long n)
  397. {
  398.   n = DNRead(io_chan, buf, n);
  399.  
  400.   if (n == -2) {
  401.     char aux;
  402.     short val, cmd;
  403.  
  404.     cmd = DGetIoctl(io_chan, &val, &aux);
  405.     if (cmd != -1) {
  406.       handleioctl(cmd, val, aux);
  407.     }
  408.     return 0;
  409.   } else 
  410.     return n;
  411. }
  412.  
  413. long nwrite_dnet(char *buf, long length)
  414. {
  415.   return DWrite(io_chan, buf, length);
  416. }
  417.  
  418. /*
  419.  * Inform the other end of connection about window size changes
  420.  */
  421. void niosize_dnet(ushort ws_row, ushort ws_col, 
  422.           ushort ws_xpixel, ushort ws_ypixel)
  423. {
  424.   DIoctl(io_chan, CIO_SETROWS, ws_row, 0);
  425.   DIoctl(io_chan, CIO_SETCOLS, ws_col, 0);
  426. }
  427.  
  428. /*
  429.  * Send ioctl (flush, break &c)
  430.  */
  431. void nioctl_dnet(int code, int arg1, int arg2)
  432. {
  433.   DIoctl(io_chan, code, arg1, arg2);
  434. }
  435.  
  436. void nclose_dnet(void)
  437. {
  438.   if (io_chan)
  439.     DClose(io_chan);
  440. }
  441.  
  442. #define nabort_dnet      nabort_generic
  443.  
  444. struct niotable nio_dnet = { 
  445.   nopen_dnet,   nnread_dnet,   nwrite_dnet, 
  446.   niosize_dnet, nioctl_dnet,   nclose_dnet,
  447.   nabort_dnet,  
  448. };
  449. #endif /* USE_DNET */
  450.  
  451. #if USE_RLOGIN || USE_TELNET
  452. /* 
  453.  * Common parts for rlogin and telnet 
  454.  */
  455.  
  456. #define BSDSOCKET_H
  457. #include <sys/param.h>
  458. #include <sys/socket.h>
  459. #include <sys/ioctl.h>
  460. #include <netinet/in.h>
  461. #include <netdb.h>
  462. #include <arpa/inet.h>
  463. #include <netinet/in_systm.h>
  464. #include <netinet/ip.h>
  465. #include <errno.h>
  466. #include <unistd.h>
  467. #include "rlogin.h"
  468. #define ioctl IoctlSocket
  469.  
  470. /* Prototypes */
  471. #ifdef USE_PRAGMAS
  472. #include <proto/socket.h>
  473. #endif
  474. #ifdef USE_INLINE
  475. #include <inline/socket.h>
  476. #endif
  477. #ifdef USE_CLIB
  478. #include <clib/socket_protos.h>
  479. #endif
  480.  
  481. struct Library *SocketBase = NULL;
  482.  
  483. #ifdef USE_GETUID
  484. #ifdef USE_PRAGMAS
  485. #include <proto/usergroup.h>
  486. #elif USE_INLINE
  487. #include <inline/usergroup.h>
  488. #else
  489. #include <clib/usergroup_protos.h>
  490. #endif
  491. #include <pwd.h>
  492. struct Library *UserGroupBase = NULL;
  493. #endif
  494.  
  495. /*
  496.  * Chose a random member of the hostvector
  497.  */
  498. const char *random_host(const char **hostvector)
  499. {
  500.   static union {
  501.     struct timeval time;
  502.     UBYTE          bytes[8];
  503.   } seed;
  504.   const char *host;
  505.   int rnd, hosts;
  506.  
  507.   for (hosts = 0; hostvector[hosts]; hosts++)
  508.     ;
  509.  
  510.   if (hosts == 0) 
  511.     return NULL;
  512.   
  513.   GetSysTime(&seed.time);
  514.   
  515.   rnd = (seed.bytes[0] + seed.bytes[1] + seed.bytes[2] + seed.bytes[3] +
  516.     seed.bytes[4] + seed.bytes[5] + seed.bytes[6] + seed.bytes[7]) 
  517.     % hosts;
  518.  
  519.  
  520.   host = hostvector[rnd]; 
  521.   
  522.   /* Remove chosen member */
  523.   hostvector[rnd] = hostvector[hosts - 1];
  524.   hostvector[hosts - 1] = NULL;
  525.  
  526.   return host;
  527. }
  528.  
  529. const char termnames[3][6] = { "vt102", "vt52", "h19" };
  530.  
  531. /* Common global variables */
  532. int rsock = -1;
  533.  
  534. BYTE IO_bit = -1;
  535. BYTE URG_bit = -1;
  536. ULONG SIGURG = 0;
  537.  
  538. /* Is it OK to send window size reports */
  539. char okwinch = 0;
  540. /* Current window size */
  541. struct winsize_packet winsize = { 0 };
  542.  
  543. #endif
  544.  
  545. #if USE_RLOGIN
  546.  
  547. /*
  548.  * Open a nio channel
  549.  */
  550. long nopen_rlogin(char **hostvector)
  551. {
  552.   long iomask;
  553.   int true = 1;
  554.   struct servent *sp;
  555.   char *user, *remote;
  556.   char term[32]; 
  557.   const char *host;
  558.  
  559.   SocketBase = OpenLibrary("bsdsocket.library", 3L);
  560.   if (!SocketBase) {
  561.     fatalError("unable to open BSD socket library");
  562.   } 
  563.  
  564.   SetErrnoPtr(&errno, sizeof(errno));
  565.  
  566.   IO_bit = AllocSignal(-1); 
  567.   URG_bit = AllocSignal(-1); 
  568.  
  569.   iomask = 1 << IO_bit;
  570.   SIGURG = 1 << URG_bit;
  571.  
  572.   SetSocketSignals(SIGBREAKF_CTRL_C, iomask, SIGURG|iomask);
  573.  
  574.   sp = getservbyname("login", "tcp");
  575.   if (sp == NULL) {
  576.     fatalError("login/tcp: unknown service");
  577.   }
  578.  
  579.   /* Local username */
  580. #ifdef USE_GETUID
  581.   if (UserGroupBase = OpenLibrary(USERGROUPNAME, 2)) 
  582.     {
  583.       struct passwd *pw = getpwuid(getuid());
  584.       if (pw) 
  585.     user = pw->pw_name;
  586.       else
  587.     user = "nobody";
  588.     } 
  589.   else 
  590. #endif
  591.     {
  592.       user = getenv("USER");
  593.       if (!user) user = "nobody";
  594.     }
  595.  
  596.   /* Our username in remote system */
  597.   remote = np.remotename ? np.remotename : user;
  598.  
  599.   /* terminal type is catenated with "/" and line speed */ 
  600.   strcpy(term, np.remoteterm ? np.remoteterm : termnames[np.emulation]);
  601.   strncat(term, "/", sizeof(term));
  602.   strncat(term, itos(np.bps), sizeof(term));
  603.  
  604.   /* Get the host name to use */
  605.   host = random_host(hostvector);
  606.   if (host == NULL) {
  607.     fatalError("no host specified.");
  608.   }
  609.  
  610.   /* Open remote login session */
  611.   rsock = rcmd(&host, sp->s_port, user, remote, term, NULL);
  612.   if (rsock < 0) {
  613.     fatalError("rmcd(): %s", strerror(errno));
  614.   }
  615.  
  616.   /* Set title to remote host name */
  617.   /* (This has no effect if title is explicitly set) */
  618.   if (!np.title) {
  619.     np.title = (char *)host;
  620.     setnewtitle();
  621.   }
  622.  
  623.   /* Set Signal driven IO */
  624. #if USE_FIONBIO
  625.   ioctl(rsock, FIONBIO, (char*)&true); 
  626. #endif
  627.   ioctl(rsock, FIOASYNC, (char*)&true);
  628.   true = IPTOS_LOWDELAY;
  629.   (void)setsockopt(rsock, IPPROTO_IP, IP_TOS, (char *)&true, sizeof(int));
  630.  
  631. #ifdef USE_GETUID
  632.   /*
  633.    * We don't need this any more
  634.    */
  635.   if (UserGroupBase) {
  636.     CloseLibrary(UserGroupBase);
  637.     UserGroupBase = NULL;
  638.   }
  639. #endif
  640.  
  641.   return iomask;
  642. }
  643.  
  644. static int rread(long s, char *buf, int length);
  645.  
  646. /*
  647.  * Read from socket
  648.  */
  649. long nnread_rlogin(char *buf, long length)
  650. {
  651.   long n = 0, m; 
  652.  
  653.   if (SetSignal(0L, SIGURG) & SIGURG) {
  654.     n = rread(rsock, buf, length);
  655.     if (n >= 0) 
  656.       SetSignal(1 << IO_bit, 1 << IO_bit);
  657.     return n;
  658.   } 
  659.  
  660.   for (;;) {
  661. #if USE_FIONBIO
  662.     m = recv(rsock, buf + n, length - n, 0);
  663.     if (m < 0) {
  664.       if (errno == EWOULDBLOCK) {
  665.     return n;
  666.       } else {
  667.     return m;
  668.       }
  669.     } else if (m == 0) {
  670.       /* This may be caused by the remote socket shutdown 
  671.        * or OOB data  delivered to the socket.
  672.        */
  673.       ioctl(rsock, SIOCATMARK, (caddr_t)&m);
  674.       if (m) { 
  675.     SetSignal(SIGURG, SIGURG);
  676.       }
  677.       return n;
  678.     }
  679.     n += m;
  680. #else
  681.     /* Find out how many bytes there are waiting for us */
  682.     if (ioctl(rsock, FIONREAD, (char*)&m) < 0) {
  683.       perror("nnread FIONREAD");
  684.       return -1;
  685.     }
  686.     if (n + m > length) {
  687.       SetSignal(1 << IO_bit, 1 << IO_bit);
  688.       m = length - n;
  689.     }
  690.     if (m == 0) 
  691.       return n;
  692.     m = recv(rsock, buf + n, m, 0);
  693.     if (m > 0) {
  694.       n += m;
  695.     } else {
  696.       if (errno == EWOULDBLOCK) 
  697.     return n;
  698.       else
  699.     return m;        /* error */
  700.     }
  701. #endif
  702.   }
  703. }
  704.  
  705. long nwrite_rlogin(char *buf, long length)
  706. {
  707.   return send(rsock, buf, length, 0);
  708. }
  709.  
  710. /*
  711.  * Inform the other end of connection about window size changes
  712.  */
  713. void niosize_rlogin(ushort ws_row, ushort ws_col, 
  714.             ushort ws_xpixel, ushort ws_ypixel)
  715. {
  716.   winsize.title[0] = winsize.title[1] = 0377;
  717.   winsize.title[2] = winsize.title[3] = 's';
  718.   winsize.ws_row    = htons(ws_row);
  719.   winsize.ws_col    = htons(ws_col);
  720.   winsize.ws_xpixel = htons(ws_xpixel);
  721.   winsize.ws_ypixel = htons(ws_ypixel);
  722.  
  723.   if (okwinch) {
  724.     send(rsock, (char *)&winsize, sizeof(winsize), 0);
  725.   }
  726. }
  727.  
  728. void nclose_rlogin(void)
  729. {
  730.   if (rsock != -1) 
  731.     CloseSocket(rsock), rsock = -1;
  732.   if (IO_bit != -1)
  733.     FreeSignal(IO_bit), IO_bit = -1;
  734.   if (URG_bit != -1)
  735.     FreeSignal(URG_bit), URG_bit = -1;
  736.   if (SocketBase)
  737.     CloseLibrary(SocketBase), SocketBase = NULL;
  738. #ifdef USE_GETUID
  739.   if (UserGroupBase)
  740.     CloseLibrary(UserGroupBase), UserGroupBase = NULL;
  741. #endif
  742. }
  743.     
  744. /*
  745.  * Read next OOB data
  746.  */
  747. static int rread(long s, char *buf, int length)
  748. {
  749.   char tiop;
  750.   int n = 0, m; 
  751.   int wasting = 0;
  752.  
  753.   for (;;) {
  754.     /* We are at OOB data? */
  755.     ioctl(s, SIOCATMARK, (caddr_t)&m);
  756.     if (m) {
  757.       m = recv(s, &tiop, 1, MSG_OOB);
  758.       if (m < 0) break;
  759.  
  760.       if (tiop & TIOCPKT_WINDOW) {
  761.     /* Let server know about window size changes */
  762.     okwinch = 1;
  763.     if (winsize.title[0])
  764.       send(rsock, (char *)&winsize, sizeof(winsize), 0);
  765.       }
  766.       /* Here we might want to handle other bits */
  767.       if (tiop & TIOCPKT_FLUSHWRITE) {
  768.     for (;;) {
  769.       if (ioctl(s, SIOCATMARK, (caddr_t)&m) < 0) {
  770.         (void)perror(PROGNAME ": ioctl");
  771.         n = -1;
  772.         break;
  773.       }
  774.       if (m) break;
  775.       n = recv(s, inbuf, sizeof (inbuf), 0);
  776.       if (n <= 0) break;
  777.     }
  778.     n = 0;
  779.       }
  780.  
  781. #if USE_FIONBIO
  782.       /* SIGIO may not be sent for the rest of buffered data */
  783.       if (length > 0) {
  784.     m = recv(s, buf, length, 0);
  785.     if (m >= 0) {
  786.       n += m;
  787.       return n;
  788.     } else if (errno == EWOULDBLOCK) {
  789.       return n;
  790.     } else {
  791.       return -1;
  792.     }
  793.       } 
  794. #else   
  795.       /* There is a bug in socket code that jams without this.. */
  796.       recv(s, inbuf, 0, 0);
  797. #endif
  798.       return n;
  799.     }
  800.     if ((m = recv(s, buf, length, 0)) < 0) 
  801.       break;
  802.     if (wasting) 
  803.       continue;
  804.     n += m; buf +=m; length -= m;
  805.     if (length > 0) continue;
  806.     wasting = 1; buf = inbuf; length = sizeof(inbuf); 
  807.   } 
  808.  
  809.   return n;
  810. }
  811.  
  812. #define nioctl_rlogin     nioctl_generic
  813. #define nabort_rlogin     nabort_generic
  814.  
  815. struct niotable nio_rlogin = { 
  816.   nopen_rlogin,   nnread_rlogin,   nwrite_rlogin, 
  817.   niosize_rlogin, nioctl_rlogin,   nclose_rlogin, 
  818.   nabort_rlogin,  
  819. };
  820. #endif /* USE_RLOGIN */
  821.  
  822. #if USE_STDIO
  823. /*
  824.  * DOS IO routines
  825.  */
  826.  
  827. struct FileHandle *io_fh;
  828. struct StandardPacket *inpkt = NULL;
  829.  
  830. /*
  831.  * Initialize DOS packet with standard args
  832.  */
  833. static void initpkt(LONG action, ULONG arg1, ULONG arg2)
  834. {
  835.   inpkt->sp_Msg.mn_Node.ln_Name = (char *)&(inpkt->sp_Pkt);
  836.   inpkt->sp_Pkt.dp_Link = &inpkt->sp_Msg;
  837.   inpkt->sp_Pkt.dp_Port = iop;
  838.   inpkt->sp_Pkt.dp_Type = action;
  839.   inpkt->sp_Pkt.dp_Arg1 = io_fh->fh_Arg1;
  840.   inpkt->sp_Pkt.dp_Arg2 = arg1;
  841.   inpkt->sp_Pkt.dp_Arg3 = arg2;
  842. }
  843.  
  844. /*
  845.  * Open a nio channel
  846.  */
  847. long nopen_stdio(char **hv)
  848. {
  849.   struct Process *me = (struct Process *)FindTask(0L);
  850.   io_fh = (struct FileHandle *)BADDR(me->pr_CIS);
  851.  
  852.   iop = CreateMsgPort();
  853.   if (iop)
  854.     inpkt = (struct StandardPacket *)CreateIORequest(iop, sizeof(*inpkt));
  855.   
  856.   if (!iop || !inpkt) {
  857.     fatalError("trouble opening stdin");
  858.   }
  859.  
  860.   initpkt(ACTION_WAIT_CHAR, 1000000L, 0);
  861.   PutMsg(io_fh->fh_Type, (struct Message *)inpkt);
  862.  
  863.   return 1 << iop->mp_SigBit;
  864. }
  865.  
  866. long nnread_stdio(char *buf, long length)
  867. {
  868.   long ret = 0;
  869.  
  870.   GetMsg(iop);
  871.  
  872.   if (inpkt->sp_Pkt.dp_Res1) {
  873.     initpkt(ACTION_READ, (ULONG)inbuf, sizeof(inbuf));
  874.     PutMsg(io_fh->fh_Type, (struct Message *)inpkt);
  875.     Wait(1 << iop->mp_SigBit);
  876.     GetMsg(iop);
  877.  
  878.     ret = inpkt->sp_Pkt.dp_Res1;
  879.     if (ret != 0) {
  880.       CopyMem(inbuf, buf, ret);
  881.     } else {
  882.       ret = -1;
  883.     }
  884.   }
  885.  
  886.   initpkt(ACTION_WAIT_CHAR, 1000000L, 0);
  887.   PutMsg(io_fh->fh_Type, (struct Message *)inpkt);
  888.   return ret;
  889. }
  890.  
  891. long nwrite_stdio(char *buf, long length)
  892. {
  893.   return Write(Output(), buf, length);
  894. }
  895.  
  896. void nclose_stdio(void)
  897. {
  898.   if (inpkt) {
  899.     /* Should we wait for reply? */ 
  900.     WaitPort(iop);
  901.     DeleteIORequest(inpkt);
  902.     inpkt = NULL;
  903.   }
  904.   if (iop) {
  905.     DeleteMsgPort(iop);
  906.     iop = NULL;
  907.   }
  908. }
  909.  
  910. #define niosize_stdio   niosize_generic
  911. #define nioctl_stdio    nioctl_generic
  912. #define nabort_stdio    nabort_generic
  913.  
  914. struct niotable nio_stdio = { 
  915.   nopen_stdio,   nnread_stdio,   nwrite_stdio, 
  916.   niosize_stdio, nioctl_stdio,   nclose_stdio,
  917.   nabort_stdio,  
  918. };
  919. #endif /* USE_STDIO */
  920.  
  921. #if USE_TELNET
  922.  
  923. #include <arpa/telnet.h>
  924. #include "telnet.h"
  925.  
  926. /*
  927.  * Open a nio channel to telnet 
  928.  */
  929. long nopen_telnet(char **hostvector)
  930. {
  931.   long iomask;
  932.   struct servent *sp;
  933.   long port;
  934.   const char *host;
  935.  
  936.   SocketBase = OpenLibrary("bsdsocket.library", 3L);
  937.   if (!SocketBase) {
  938.     fatalError("unable to open BSD socket library");
  939.   } 
  940.  
  941.   SetErrnoPtr(&errno, sizeof errno);
  942.  
  943.   IO_bit = AllocSignal(-1);
  944.   URG_bit = AllocSignal(-1); 
  945.  
  946.   iomask = 1 << IO_bit;
  947.   SIGURG = 1 << URG_bit;
  948.  
  949.   SetSocketSignals(SIGBREAKF_CTRL_C, iomask, SIGURG|iomask);
  950.  
  951.   sp = getservbyname(np.service, "tcp");
  952.   if (sp == NULL && StrToLong(np.service, &port) <= 0) {
  953.     fatalError("%s/tcp: unknown service", np.service);
  954.   }
  955.  
  956.   /* Get the host name to use */
  957.   host = random_host(hostvector);
  958.   if (host == NULL) {
  959.     fatalError("no host specified.");
  960.   }
  961.  
  962.   /* open telnet session */
  963.   if ((rsock = socket(AF_INET, SOCK_STREAM, 0)) != -1) {
  964.     struct sockaddr_in addr = { 0 };
  965.     struct hostent * h;
  966.     int true = 1;
  967.     long pid = (long)getpid();
  968.  
  969.     /* Set Signal driven IO */
  970.     ioctl(rsock, FIOSETOWN, (caddr_t)&pid);
  971.     ioctl(rsock, FIOASYNC, (char*)&true);
  972.     setsockopt(rsock, SOL_SOCKET, SO_OOBINLINE, (char *)&true, sizeof(true));
  973.     true = IPTOS_LOWDELAY;
  974.     setsockopt(rsock, IPPROTO_IP, IP_TOS, (char *)&true, sizeof(true));
  975.  
  976.     addr.sin_family = AF_INET;
  977.     if (sp != NULL)
  978.       addr.sin_port = sp->s_port;
  979.     else
  980.       addr.sin_port = port;
  981.       
  982.     if ((h = gethostbyname(host)) == NULL)
  983.       fatalError("gethostbyname: %s\n", "no such beast"); /*XXX*/
  984.  
  985.     bcopy(h->h_addr, &addr.sin_addr.s_addr, sizeof (struct in_addr));
  986.  
  987.     if (connect(rsock, (struct sockaddr *)&addr, sizeof addr) == -1)
  988.       fatalError("connect: %s\n", strerror(errno));
  989.   } else {
  990.     fatalError("socket: %s\n", strerror(errno));
  991.   }
  992.   
  993.   /* Set title to remote host name */
  994.   /* (This has no effect if title is explicitly set) */
  995.   if (!np.title) {
  996.     np.title = (char *)host;
  997.     setnewtitle();
  998.   }
  999.  
  1000.   return iomask;
  1001. }
  1002.  
  1003. /*
  1004.  * Read from socket
  1005.  */
  1006. long nnread_telnet(char *buf, long length)
  1007. {
  1008.   long n = 0, m; 
  1009.  
  1010. #if 0 /*XXX*/
  1011.   if (SetSignal(0L, SIGURG) & SIGURG) {
  1012.     /* Handle urgent data (SYNC) */
  1013.     
  1014.   } 
  1015. #endif
  1016.  
  1017.   for (;;) {
  1018.     /* Find out how many bytes there are waiting for us */
  1019.     if (ioctl(rsock, FIONREAD, (char*)&m) < 0) {
  1020.       perror("nnread FIONREAD");
  1021.       return -1;
  1022.     }
  1023.  
  1024.     /* If there is too much data for our buffer... */
  1025.     if (n + m > length) {
  1026.       /* ... continue, set signal for us */
  1027.       SetSignal(1 << IO_bit, 1 << IO_bit);
  1028.       m = length - n;
  1029.     }
  1030.  
  1031.     /* No more data, call telnet protocol machine and return */
  1032.     if (m == 0) {
  1033.       return telnetdo(buf, n);
  1034.     }
  1035.  
  1036.     m = recv(rsock, buf + n, m, 0);
  1037.  
  1038.     if (m != -1) {
  1039.       n += m;
  1040.     } else {
  1041.       if (errno == EWOULDBLOCK) 
  1042.     /* Call telnet protocol machine and return */
  1043.     return telnetdo(buf, n);
  1044.       else
  1045.     return -1;        /* error */
  1046.     }
  1047.   }
  1048. }
  1049.  
  1050. /*
  1051.  * Write the buffer into telnet
  1052.  */
  1053. long nwrite_telnet(char *buf, long length)
  1054. {
  1055.   long i;
  1056.  
  1057.   for (i = 0; i < length; i++) {
  1058.     register char c = buf[i];
  1059.  
  1060.     /* We are supposed to quote these */
  1061.     if (c == 0xff || c == 0x0d) {
  1062.       /* 
  1063.        * We must quote the buffer 
  1064.        */
  1065.       char telnet_buffer[TELNETBUFFERSIZE];
  1066.       long count;
  1067.  
  1068.       /* 
  1069.        * If there is a lot of stuff to send, do it without copying
  1070.        */
  1071.       if (i >= TELNETBUFFERSIZE / 2) {
  1072.     if (send(rsock, buf, i, 0) == -1)
  1073.       return -1;
  1074.     count = 0;
  1075.       } else {
  1076.     memcpy(telnet_buffer, buf, count = i);
  1077.       }
  1078.  
  1079.       /*
  1080.        * Quote and copy
  1081.        */
  1082.       for (; i < length; i++) {
  1083.     switch (c = buf[i]) {
  1084.     case 0xff:
  1085.       telnet_buffer[count++] = c;
  1086.       break;
  1087.     case 0x0d:
  1088.       telnet_buffer[count++] = c;
  1089.       c = '\0';
  1090.       break;
  1091.     }
  1092.  
  1093.     telnet_buffer[count++] = c;
  1094.  
  1095.     /* If our quoting buffer overflows, send it */
  1096.     if (count >= TELNETBUFFERSIZE - 1) {
  1097.       if (send(rsock, telnet_buffer, count, 0) == -1)
  1098.         return -1;
  1099.       count = 0;
  1100.     }
  1101.       }
  1102.  
  1103.       /* Send the quoted buffer */
  1104.       if (count > 0 && send(rsock, telnet_buffer, count, 0) == -1)
  1105.     return -1;
  1106.     
  1107.       return length;
  1108.     }
  1109.   }
  1110.  
  1111.   /* There was no characters to quote, send as it is */
  1112.   return send(rsock, buf, length, 0);
  1113. }
  1114.  
  1115. /*
  1116.  * Current window size
  1117.  */
  1118. static ushort ws_row_stored, ws_col_stored;
  1119.  
  1120. /* 
  1121.  * Do IAC SB NAWS 
  1122.  */
  1123. extern void do_naws(void)
  1124. {
  1125.   u_char buf[3 + 4 + 4 + 2], *p = buf;
  1126.  
  1127.   *p++ = IAC;
  1128.   *p++ = SB;
  1129.   *p++ = TELOPT_NAWS;
  1130.  
  1131.   /* We must quote IACs */
  1132.   if ((ws_col_stored >> 8) == IAC) {
  1133.     *p++ = IAC;
  1134.   }
  1135.   *p++ = ws_col_stored >> 8;
  1136.   if ((ws_col_stored & 0xff) == IAC) {
  1137.     *p++ = IAC;
  1138.   }
  1139.   *p++ = ws_col_stored & 0xff;
  1140.  
  1141.   if ((ws_row_stored >> 8) == IAC) {
  1142.     *p++ = IAC;
  1143.   }
  1144.   *p++ = ws_row_stored >> 8;
  1145.   if ((ws_row_stored & 0xff) == IAC) {
  1146.     *p++ = IAC;
  1147.   }
  1148.   *p++ = ws_row_stored & 0xff;
  1149.  
  1150.   *p++ = IAC;
  1151.   *p++ = SE;
  1152.  
  1153.   send(rsock, buf, p - buf, 0);
  1154. }
  1155.  
  1156. /*
  1157.  * Inform the other end of connection about window size changes
  1158.  */
  1159. void niosize_telnet(ushort ws_row, ushort ws_col, 
  1160.             ushort ws_xpixel, ushort ws_ypixel)
  1161. {
  1162.   /* Store winsize so we can send NAWS after IAC DO NAWS */
  1163.   ws_row_stored = ws_row;
  1164.   ws_col_stored = ws_col;
  1165.  
  1166.   /* Do we have received IAC DO NAWS ? */
  1167.   if (okwinch) {
  1168.     do_naws();
  1169.   }
  1170. }
  1171.  
  1172. void nclose_telnet(void)
  1173. {
  1174.   if (rsock != -1) 
  1175.     CloseSocket(rsock), rsock = -1;
  1176.   if (IO_bit != -1)
  1177.     FreeSignal(IO_bit), IO_bit = -1;
  1178.   if (URG_bit != -1)
  1179.     FreeSignal(URG_bit), URG_bit = -1;
  1180.   if (SocketBase)
  1181.     CloseLibrary(SocketBase), SocketBase = NULL;
  1182. }
  1183.     
  1184. #define nioctl_telnet     nioctl_generic
  1185. #define nabort_telnet     nabort_generic
  1186.  
  1187. struct niotable nio_telnet = { 
  1188.   nopen_telnet,   nnread_telnet,   nwrite_telnet, 
  1189.   niosize_telnet, nioctl_telnet,   nclose_telnet, 
  1190.   nabort_telnet,  
  1191. };
  1192.  
  1193. #endif /* USE_TELNET */
  1194.